package com.movies.service.controller.user;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.movies.service.common.Constants;
import com.movies.service.common.Result;
import com.movies.service.entity.Ticket;
import com.movies.service.entity.User;
import com.movies.service.entity.Cinema;
import com.movies.service.entity.Seat;
import com.movies.service.service.TicketService;
import com.movies.service.service.UserService;
import com.movies.service.service.CinemaService;
import com.movies.service.service.SeatService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;


@RestController
@RequestMapping("/user/ticket")
@SaCheckLogin
public class UserTicketController {

    @Autowired
    private TicketService ticketService;
    @Autowired
    private UserService userService;
    @Autowired
    private CinemaService cinemaService;
    @Autowired
    private SeatService seatService;

//    分页查询当前用户的订单（可按状态筛选）
    @GetMapping("/page")
    public Result page(@RequestParam(defaultValue = "1") Integer pageNo,
            @RequestParam(defaultValue = "10") Integer pageSize,
            @RequestParam(required = false) String status) {
        Long uid = StpUtil.getLoginIdAsLong();
        LambdaQueryWrapper<Ticket> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Ticket::getUid, uid)
                .eq(status != null && !status.isEmpty(), Ticket::getStatus, status);
        Page<Ticket> page = ticketService.page(new Page<>(pageNo, pageSize), wrapper);
        return Result.success(page);
    }

//    获取订单详情
    @GetMapping("/{id}")
    public Result get(@PathVariable Long id) {
        Long uid = StpUtil.getLoginIdAsLong();
        Ticket t = ticketService.getById(id);
        if (t == null || !uid.equals(t.getUid())) {
            return Result.error(Constants.CODE_401, "无权查看该订单");
        }
        ensureCinemaSnapshot(t);
        return Result.success(t);
    }

//    创建订单（购买电影），默认未支付
    @PostMapping
    public Result create(@RequestBody CreateTicketReq req) {
        Long uid = StpUtil.getLoginIdAsLong();
        User user = (User) StpUtil.getSession().get("user");
        if (user == null) {
            user = userService.getById(uid);
        }
        // 校验影院
        if (req.getCinemaId() == null) {
            return Result.error(Constants.CODE_600, "下单必须指定影院");
        }
        Cinema cinema = cinemaService.getById(req.getCinemaId());
        if (cinema == null) {
            return Result.error(Constants.CODE_600, "影院不存在");
        }
        String cStatus = String.valueOf(cinema.getStatus());
        if (!"OPEN".equalsIgnoreCase(cStatus)) {
            return Result.error(Constants.CODE_600, "该影院已停业，无法购票");
        }
        // 校验影厅
        if (req.getHallName() == null || req.getHallName().isEmpty()) {
            return Result.error(Constants.CODE_600, "必须选择影厅");
        }
        try {
            ObjectMapper mapper = new ObjectMapper();
            String hallRaw = cinema.getHallList();
            if (hallRaw == null || hallRaw.trim().isEmpty() || "null".equalsIgnoreCase(hallRaw.trim())) {
                hallRaw = "[]";
            }
            List<String> halls = mapper.readValue(hallRaw, new TypeReference<List<String>>() {
            });
            if (halls == null || !halls.contains(req.getHallName())) {
                return Result.error(Constants.CODE_600, "影厅不存在：" + req.getHallName());
            }
        } catch (Exception e) {
            return Result.error(Constants.CODE_600, "影厅配置异常，请联系管理员");
        }
        // 校验座位
        if (req.getSeatLabel() == null || req.getSeatLabel().isEmpty()) {
            return Result.error(Constants.CODE_600, "必须选择座位号");
        }
        List<String> seats = Arrays.stream(req.getSeatLabel().split(","))
                .map(String::trim).filter(s -> !s.isEmpty()).collect(java.util.stream.Collectors.toList());
        if (seats.isEmpty()) {
            return Result.error(Constants.CODE_600, "座位号格式不正确");
        }
        LambdaQueryWrapper<Seat> seatWrapper = new LambdaQueryWrapper<>();
        seatWrapper.eq(Seat::getCinemaId, req.getCinemaId())
                .eq(Seat::getHallName, req.getHallName())
                .in(Seat::getSeatNo, seats);
        long found = seatService.count(seatWrapper);
        if (found != seats.size()) {
            return Result.error(Constants.CODE_600, "部分座位不存在或不可选");
        }

        // 组装订单（创建为未支付，不做扣款）
        int qty = (req.getQuantity() != null && req.getQuantity() > 0) ? req.getQuantity() : 1;

        Ticket t = new Ticket();
        t.setUid(uid);
        t.setUname(user != null ? user.getUname() : null);
        t.setMid(req.getMid());
        t.setMname(req.getMname());
        t.setQuantity(qty);
        // 价格为总价字段，非单价；数据库 price NOT NULL
        t.setPrice(req.getPrice() != null ? req.getPrice() : BigDecimal.ZERO);
        // 快照字段（持久化影院ID与名称）
        t.setCinemaId(req.getCinemaId());
        t.setCinemaName(cinema.getCname());
        t.setCinemaAddress(cinema.getAddress());
        t.setHallName(req.getHallName());
        t.setSeatLabel(req.getSeatLabel());
        t.setTtime(new Date());
        t.setStatus("UNPAID");
        t.setNote(req.getNote());
        boolean ok = ticketService.save(t);
        return ok ? Result.success("创建成功", t) : Result.error(Constants.CODE_600, "创建失败");
    }

//    购票（扣减余额并创建已支付订单）
    @PostMapping("/buy")
    public Result buy(@RequestBody BuyTicketReq req) {
        Long uid = StpUtil.getLoginIdAsLong();
        User user = (User) StpUtil.getSession().get("user");
        if (user == null) {
            user = userService.getById(uid);
        }
        if (user == null) {
            return Result.error(Constants.CODE_600, "用户不存在");
        }
        // 校验影院
        if (req.getCinemaId() == null) {
            return Result.error(Constants.CODE_600, "下单必须指定影院");
        }
        Cinema cinema = cinemaService.getById(req.getCinemaId());
        if (cinema == null) {
            return Result.error(Constants.CODE_600, "影院不存在");
        }
        String cStatus = String.valueOf(cinema.getStatus());
        if (!"OPEN".equalsIgnoreCase(cStatus)) {
            return Result.error(Constants.CODE_600, "该影院已停业，无法购票");
        }
        // 校验影厅
        if (req.getHallName() == null || req.getHallName().isEmpty()) {
            return Result.error(Constants.CODE_600, "必须选择影厅");
        }
        try {
            ObjectMapper mapper = new ObjectMapper();
            String hallRaw = cinema.getHallList();
            if (hallRaw == null || hallRaw.trim().isEmpty() || "null".equalsIgnoreCase(hallRaw.trim())) {
                hallRaw = "[]";
            }
            List<String> halls = mapper.readValue(hallRaw, new TypeReference<List<String>>() {
            });
            if (halls == null || !halls.contains(req.getHallName())) {
                return Result.error(Constants.CODE_600, "影厅不存在：" + req.getHallName());
            }
        } catch (Exception e) {
            return Result.error(Constants.CODE_600, "影厅配置异常，请联系管理员");
        }
        // 校验座位
        if (req.getSeatLabel() == null || req.getSeatLabel().isEmpty()) {
            return Result.error(Constants.CODE_600, "必须选择座位号");
        }
        List<String> seats = Arrays.stream(req.getSeatLabel().split(","))
                .map(String::trim).filter(s -> !s.isEmpty()).collect(java.util.stream.Collectors.toList());
        if (seats.isEmpty()) {
            return Result.error(Constants.CODE_600, "座位号格式不正确");
        }
        LambdaQueryWrapper<Seat> seatWrapper = new LambdaQueryWrapper<>();
        seatWrapper.eq(Seat::getCinemaId, req.getCinemaId())
                .eq(Seat::getHallName, req.getHallName())
                .in(Seat::getSeatNo, seats);
        long found = seatService.count(seatWrapper);
        if (found != seats.size()) {
            return Result.error(Constants.CODE_600, "部分座位不存在或不可选");
        }

        // 余额扣减：校验单价与数量并扣款
        int qty = (req.getQuantity() != null && req.getQuantity() > 0) ? req.getQuantity() : 1;
        BigDecimal unit = req.getUnitPrice() != null ? req.getUnitPrice() : BigDecimal.ZERO;
        if (unit.compareTo(BigDecimal.ZERO) <= 0) {
            return Result.error(Constants.CODE_600, "单价必须大于0");
        }
        BigDecimal total = unit.multiply(BigDecimal.valueOf(qty));
        if (user.getBalance() == null) {
            user.setBalance(BigDecimal.ZERO);
        }
        if (user.getBalance().compareTo(total) < 0) {
            return Result.error(Constants.CODE_600, "余额不足，请先充值");
        }
        user.setBalance(user.getBalance().subtract(total));
        boolean userOk = userService.updateById(user);
        if (!userOk) {
            return Result.error(Constants.CODE_600, "扣款失败，请稍后重试");
        }

        Ticket t = new Ticket();
        t.setUid(uid);
        t.setUname(user.getUname());
        t.setMid(req.getMid());
        t.setMname(req.getMname());
        t.setQuantity(req.getQuantity());
        t.setPrice(req.getUnitPrice() != null && req.getQuantity() != null
                ? req.getUnitPrice().multiply(new BigDecimal(req.getQuantity()))
                : null);
        // 快照字段（持久化影院ID与名称）
        t.setCinemaId(req.getCinemaId());
        t.setCinemaName(cinema.getCname());
        t.setCinemaAddress(cinema.getAddress());
        t.setHallName(req.getHallName());
        t.setSeatLabel(req.getSeatLabel());
        t.setTtime(new Date());
        t.setStatus("PAID");
        t.setNote(req.getNote());
        boolean ok = ticketService.save(t);
        return ok ? Result.success("购票成功", t) : Result.error(Constants.CODE_600, "购票失败");
    }

//    更新订单（仅限本人，可更新状态与备注）
    @PutMapping
    public Result update(@RequestBody UpdateTicketReq req) {
        Long uid = StpUtil.getLoginIdAsLong();
        Ticket t = ticketService.getById(req.getId());
        if (t == null || !uid.equals(t.getUid())) {
            return Result.error(Constants.CODE_401, "无权操作该订单");
        }
        if (req.getStatus() != null) {
            t.setStatus(req.getStatus());
        }
        t.setNote(req.getNote());
        boolean ok = ticketService.updateById(t);
        return ok ? Result.success("更新成功") : Result.error(Constants.CODE_600, "更新失败");
    }

    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Long id) {
        Long uid = StpUtil.getLoginIdAsLong();
        Ticket t = ticketService.getById(id);
        if (t == null || !uid.equals(t.getUid())) {
            return Result.error(Constants.CODE_401, "无权操作该订单");
        }
        boolean ok = ticketService.removeById(id);
        return ok ? Result.success("删除成功") : Result.error(Constants.CODE_600, "删除失败");
    }

//    创建订单请求体
    public static class CreateTicketReq {
        private Long mid;
        private String mname;
        private BigDecimal price;
        private Integer quantity;
        private String note; // 富文本备注
        private Long cinemaId; // 影院ID（用于校验与快照）
        private String hallName; // 影厅
        private String seatLabel; // 座位号（可多座，用逗号分隔）

        public Long getMid() {
            return mid;
        }

        public void setMid(Long mid) {
            this.mid = mid;
        }

        public String getMname() {
            return mname;
        }

        public void setMname(String mname) {
            this.mname = mname;
        }

        public BigDecimal getPrice() {
            return price;
        }

        public void setPrice(BigDecimal price) {
            this.price = price;
        }

        public Integer getQuantity() {
            return quantity;
        }

        public void setQuantity(Integer quantity) {
            this.quantity = quantity;
        }

        public String getNote() {
            return note;
        }

        public void setNote(String note) {
            this.note = note;
        }

        public Long getCinemaId() {
            return cinemaId;
        }

        public void setCinemaId(Long cinemaId) {
            this.cinemaId = cinemaId;
        }

        public String getHallName() {
            return hallName;
        }

        public void setHallName(String hallName) {
            this.hallName = hallName;
        }

        public String getSeatLabel() {
            return seatLabel;
        }

        public void setSeatLabel(String seatLabel) {
            this.seatLabel = seatLabel;
        }
    }

//    购票请求体
    public static class BuyTicketReq {
        private Long mid;
        private String mname;
        private BigDecimal unitPrice; // 单价
        private Integer quantity; // 购买数量
        private String note; // 备注
        private Long cinemaId; // 影院ID（用于校验与快照）
        private String hallName; // 影厅
        private String seatLabel; // 座位号（可多座，用逗号分隔）

        public Long getMid() {
            return mid;
        }

        public void setMid(Long mid) {
            this.mid = mid;
        }

        public String getMname() {
            return mname;
        }

        public void setMname(String mname) {
            this.mname = mname;
        }

        public BigDecimal getUnitPrice() {
            return unitPrice;
        }

        public void setUnitPrice(BigDecimal unitPrice) {
            this.unitPrice = unitPrice;
        }

        public Integer getQuantity() {
            return quantity;
        }

        public void setQuantity(Integer quantity) {
            this.quantity = quantity;
        }

        public String getNote() {
            return note;
        }

        public void setNote(String note) {
            this.note = note;
        }

        public Long getCinemaId() {
            return cinemaId;
        }

        public void setCinemaId(Long cinemaId) {
            this.cinemaId = cinemaId;
        }

        public String getHallName() {
            return hallName;
        }

        public void setHallName(String hallName) {
            this.hallName = hallName;
        }

        public String getSeatLabel() {
            return seatLabel;
        }

        public void setSeatLabel(String seatLabel) {
            this.seatLabel = seatLabel;
        }
    }

    /** 更新订单请求体 */
    public static class UpdateTicketReq {
        private Long id;
        private String status; // PAID/UNPAID
        private String note; // 富文本备注

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }

        public String getNote() {
            return note;
        }

        public void setNote(String note) {
            this.note = note;
        }
    }

    /**
     * 兜底填充影院快照（ID/名称），避免旧订单缺失导致前端显示为空。
     * 优先使用持久化字段；缺失时按“座位→影院”或“地址→影院”回填，仅设置到内存对象中。
     * 
     * @param t 订单实体
     */
    private void ensureCinemaSnapshot(Ticket t) {
        if (t == null)
            return;
        boolean hasId = t.getCinemaId() != null;
        boolean hasName = t.getCinemaName() != null && !t.getCinemaName().isEmpty();
        if (hasId && hasName)
            return;
        // 尝试：座位 + 影厅 定位影院
        String firstSeat = null;
        try {
            if (t.getSeatLabel() != null) {
                String[] parts = t.getSeatLabel().split(",");
                if (parts.length > 0)
                    firstSeat = parts[0].trim();
            }
        } catch (Exception ignored) {
        }
        if (firstSeat != null && t.getHallName() != null) {
            LambdaQueryWrapper<Seat> sw = new LambdaQueryWrapper<>();
            sw.eq(Seat::getHallName, t.getHallName()).eq(Seat::getSeatNo, firstSeat);
            Seat seat = seatService.getOne(sw);
            if (seat != null) {
                if (!hasId && seat.getCinemaId() != null)
                    t.setCinemaId(seat.getCinemaId());
                if (!hasName && seat.getCinemaName() != null)
                    t.setCinemaName(seat.getCinemaName());
            }
        }
        // 若已有影院ID，补名称即可
        if (t.getCinemaId() != null) {
            if (t.getCinemaName() == null || t.getCinemaName().isEmpty()) {
                Cinema c = cinemaService.getById(t.getCinemaId());
                if (c != null)
                    t.setCinemaName(c.getCname());
            }
            return;
        }
        // 最后按地址快照匹配影院
        String addr = t.getCinemaAddress();
        if (addr != null && !addr.trim().isEmpty()) {
            LambdaQueryWrapper<Cinema> cw = new LambdaQueryWrapper<>();
            cw.eq(Cinema::getAddress, addr.trim());
            Cinema c = cinemaService.getOne(cw);
            if (c != null) {
                if (t.getCinemaId() == null)
                    t.setCinemaId(c.getId());
                if (t.getCinemaName() == null || t.getCinemaName().isEmpty())
                    t.setCinemaName(c.getCname());
            }
        }
    }
}
